
#include "dvb.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define __min(a, b)	((a)>(b)?(b):(a))
#define __max(a, b)	((a)>(b)?(a):(b))

bool DvbIsPositive(DVB dv)
{
	return((dv & NEGABIT) == 0 ? true:false);
}

bool DvbIsInteger(DVB dv)
{
	return((dv & 0x70000000) == 0 ? true:false);
}

int DotOfDvb(DVB dv)
{
	return((dv & 0x70000000) >> 28);
}

long Dvb2Int(DVB dv)
{
	static long DECIMUL[] = {1,10,100,1000,10000,100000,1000000};
	int dot = DotOfDvb(dv);
	long iv, i;
	
	if(dot != 0) {
		dv >>= (dot * 4);
	}
	iv = 0;
	for(i=0; i<(7-dot); i++) {
		iv += (long)(dv & 0x0000000f) * DECIMUL[i];
		dv >>= 4;
	}
	return((dv & 0x00000008) ? -iv : iv);
}

uint32_t Int2Dvb(long iv)
{
	bool isNega = (iv < 0);
	uint32_t shift = 0;
	uint32_t dv = 0;
	int i;
	uint32_t deci;
	
	if(isNega) {
		iv = -iv;
	}
	for(i=0; i<7; i++) {
		deci = (uint32_t)(iv%10);
		if(deci != 0) {
			dv |= (deci<<shift);
		}
		iv /= 10;
		shift += 4;
	}
	if(isNega) {
		dv |= NEGABIT;
	}
	return(dv);
}


float Dvb2Float(DVB dv)
{
	static float FMULTI[] = {1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f};

	int dot = ((dv & 0x70000000) >> 28);
	long iv = Dvb2Int(dv & 0x8FFFFFFF);
	return(iv * FMULTI[dot]);
}

static long Round2Int(float f)
{
	if(f >= 0.0f) {
		return((long)(f+0.499f));
	} else {
		return((long)(f-0.499f));
	}
}

DVB Float2Dvb(float fv, int dot)
{
	static long MULTI[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
	float mf;
	uint32_t dv;
	dot = __max(0, dot);
	dot = __min(7, dot);
	mf = fv * MULTI[dot];
	mf = __max(-9999999.0f, mf);
	mf = __min(9999999.0f, mf);
	dv = Int2Dvb(Round2Int(mf));
	return(dv | ((uint32_t)dot << 28));
}

DVB FreeFloat2Dvb(float fv)
{
	int dot = 0;
	float afv = fabsf(fv);
	int i;

	if(afv < 0.000001f) {
		return(0);
	}
	for(i=0; i<3; i++) {
		if(afv > 1.0f) {
			break;
		}
		afv *= 10.0f;
		dot++;
	}

	while((afv < 1000000.0f) && (dot < 6)) {
		if(fmodf(afv, 1.0f) < 0.001f) {
			break;
		}
		afv *= 10.0f;
		dot++;
	}

	return(Float2Dvb(fv, dot));
}

DVB ValidFloat2Dvb(float fv, int wd)
{
	float afv = fabsf(fv);
	int intWd = 1;
	int dot;
	
	while(afv > 9.9999f) {
		intWd++;
		afv /= 10;
	}

	if(intWd >=  wd) {
		dot = 0;
	} else {
		dot = wd - intWd;
	}
	return(Float2Dvb(fv, dot));
}

void Dvb2String(char strBuf[], uint32_t dv)
{
	bool negative = !DvbIsPositive(dv);
	int dot = DotOfDvb(dv);
	int dwidth = 7;
	uint32_t mask = 0x0f000000;
	int i, p, stringLen, dcount;
	bool needDot;
	
	for(i=0; i<7; i++) {				// ȷ����Ч���ֿ���
		if(mask & dv) {
			break;
		}
		dwidth--;
		mask >>= 4;
	}
	if(dwidth == 0) {					// ����ȫ0
		p = 0;
		strBuf[p++] = '0';
		if(dot >= 1) {
			strBuf[p++] = '.';
			for(i=0; i<dot; i++) {
				strBuf[p++] = '0';
			}
		}
		strBuf[p++] = '\0';
		return;
	}
	if(dot == 0) {
		stringLen = dwidth;
	} else {
		stringLen = __max(dwidth+1, dot+2);
	}
	if(negative) {
		stringLen++;
	}
	strBuf[stringLen] = '\0';			// ��ĩβ��ʼ�γ��ַ���
	dcount = 0;
	needDot = (dot !=0 ) ? true:false;
	for(i=stringLen-1; i>=0; i--) {
		if(needDot && dcount == dot) {
			needDot = false;
			strBuf[i] = '.';
		}
		else if(dcount < dwidth) {
			int d = (dv & 0x0000000f);
			if(d < 10) {
				strBuf[i] = (char)(d+'0');
			} else {
				strBuf[i] = (char)(d-10+'A');
			}
			dv >>= 4;
			dcount++;
		}
		else if(i == 0 && negative) {
			strBuf[i] = '-';
		}
		else {
			strBuf[i] = '0';
			dcount++;
		}
	}
}

// ����������str��һ����ʽ���õ��ַ�����û�зǷ��ַ���������һ��С���㣬����һ������λ����Ч���ֲ�����7��
DVB String2Dvb(const char *str)
{
	int rightIndex = (int)strlen(str)-1;		// �ַ��������Ҷ�λ��
	bool negative = (str[0] == '-') ? true:false;
	int leftIndex = negative ? 1:0;				// �ַ����������λ��
	uint32_t dv = 0x00000000;
	bool dotFound = false;
	int dot = 0;
	int i;
	char c;
	
	for(i=leftIndex; i<=rightIndex; i++) {		// ����˸�λ��ʼת����������λ
		c = str[i];
		if(c == '.') {							// ����С����
			dotFound = true;
		}
		else if(c >= '0' && c <= '9') {			// ��������
			dv <<= 4;
			dv |= (c-'0');
			if(dotFound) {
				dot++;
			}
		}
	}
	if(negative) {
		dv |= NEGABIT;
	}
	if(dot > 0) {
		dv |= ((uint32_t)dot << 28);
	}
	return(dv);
}

DVB DvbAbs(DVB dv)
{
	return(dv & 0x7FFFFFFF);
}

DVB DvbNega(DVB dv)
{
	return(dv | NEGABIT);
}

DVB DvbReform(uint32_t dv, int dot)
{
	int oldDot;
	uint32_t newDvb, newDeci;
	int rightShift, leftShift;
	
	dot = __max(0, dot);
	dot = __min(7, dot);
	oldDot = DotOfDvb(dv);
	newDvb = dv;
	if (dot < oldDot) {
		rightShift = 4 * (oldDot - dot);
		newDeci = (newDvb & 0x0fffffff) >> rightShift;
		newDvb = (newDvb & NEGABIT) | ((uint32_t)dot << 28) | newDeci;
	}
	else if (dot > oldDot) {
		leftShift = 4 * (dot - oldDot);
		newDeci = (newDvb << leftShift) & 0x0fffffff;
		newDvb = (newDvb & NEGABIT) | ((uint32_t)dot << 28) | newDeci;
	}
	return(newDvb);
}

static int uint32_tCompare(uint32_t dw1, uint32_t dw2)
{
	if (dw1 > dw2) {
		return(1);
	}
	else if (dw1 < dw2) {
		return(-1);
	}
	else {
		return(0);
	}
}

int DvbCompare(DVB dv1, DVB dv2)
{
	bool p1, p2;
	int compFactor, dot1, dot2;
	uint32_t oldDvb1, oldDvb2;
	int shift1, big1, shift2, big2;
	
	if (dv1 == dv2) {
		return(0);
	}
	p1 = DvbIsPositive(dv1);
	p2 = DvbIsPositive(dv2);
	if (p1 && (!p2)) {
		return(1);
	}
	if ((!p1) && p2) {
		return(-1);
	}

	// ����������������ͬ��Ȼ��ͳһ����������λ����С���㷽��Ƚ�
	compFactor = 1;						// �ȽϷ�������
	dot1 = DotOfDvb(dv1);
	dot2 = DotOfDvb(dv2);
	if (!p1) {
		compFactor *= -1;
	}
	dv1 &= 0x0FFFFFFF;					// �������λ��С����λ
	dv2 &= 0x0FFFFFFF;
	if (dot1 < dot2) {					// ��λ��dot2����
		oldDvb1 = dv1;
		shift1 = (dot2 - dot1) * 4;
		dv1 <<= shift1;
		if ((dv1 >> shift1) != oldDvb1) {
			big1 = 1;					// dv1�����ƹ����и�λ��������Խϴ�
		}
		else {
			big1 = uint32_tCompare(dv1, dv2);
		}
		compFactor *= big1;
	}
	else if (dot1 > dot2) {				// ��λ��dot1����
		oldDvb2 = dv2;
		shift2 = (dot1 - dot2) * 4;
		dv2 <<= shift2;
		if ((dv2 >> shift2) != oldDvb2) {
			big2 = 1;					// dv2�����ƹ����и�λ��������Դ�
		}
		else {
			big2 = uint32_tCompare(dv2, dv1);
		}
		compFactor *= (-big2);
	}
	else {
		compFactor *= uint32_tCompare(dv1, dv2);
	}
	return(compFactor);
}

DVB DvbMin(DVB dv1, DVB dv2)
{
	bool posi1 = DvbIsPositive(dv1);
	bool posi2 = DvbIsPositive(dv2);

	if (posi1) {
		if (posi2) {
			return(__min(dv1, dv2));
		}
		else {
			return(dv2);
		}
	}
	else {
		if (posi2) {
			return(dv1);
		}
		else {
			return(__max(dv1, dv2));
		}
	}
}

DVB DvbMax(DVB dv1, DVB dv2)
{
	bool posi1 = DvbIsPositive(dv1);
	bool posi2 = DvbIsPositive(dv2);

	if (posi1) {
		if (posi2) {
			return(__max(dv1, dv2));
		}
		else {
			return(dv1);
		}
	}
	else {
		if (posi2) {
			return(dv2);
		}
		else {
			return(__min(dv1, dv2));
		}
	}
}

static const long IDRMUL[] = {10,100,1000,10000,100000,1000000};
static const float IDRDIV[] = {0.1f,0.01f,0.001f,0.0001f,0.00001f,0.000001f};
IDR Float2Idr(float fv, int dot)
{
	if(dot > 0 && dot < 7) {
		return(Round2Int(fv*IDRMUL[dot-1]));
	}
	else {
		return(Round2Int(fv));
	}
}

float Idr2Float(IDR idr, int dot)
{
	if(dot > 0 && dot < 7) {
		return(idr*IDRDIV[dot-1]);
	}
	else {
		return((float)idr);
	}
}

// ��ʵ�൱��Dvb2Int,����С������Ϣ,��������
long Dvb2Idr(DVB dv)
{
	uint32_t numDvb = (dv & 0x0FFFFFFF);	// ��������
	long lv = (numDvb & 0x0000000F);	// ���Ҳ�4-bit����ʮ��������������
	int i;
	long deci;
	
	for(i=0; i<6; i++) {
		numDvb >>= 4;					// �������
		if(numDvb == 0) {
			break;
		}
		deci = (numDvb & 0x0000000F);
		if(deci != 0) {
			lv += deci * IDRMUL[i];
		}
	}
	return((dv & NEGABIT) ? -lv : lv);
}

uint32_t Idr2Dvb(IDR idr, int dot)
{
	bool isNega = (idr < 0);
	long absIdr = isNega ? -idr : idr;
	uint32_t dv = (uint32_t)(absIdr%10);
	int shift = 4;
	int i;
	uint32_t deci;
	
	for(i=0; i<6; i++) {
		absIdr /= 10;
		if(absIdr == 0) {
			break;
		}
		deci = (uint32_t)(absIdr%10);
		if(deci != 0) {
			dv |= (deci<<shift);
		}
		shift += 4;
	}

	dv |= ((uint32_t)dot<<28);
	if(isNega) {
		dv |= NEGABIT;
	}
	return(dv);
}

DVB DvbInc(DVB dv, IDR idr)
{
	int dot = DotOfDvb(dv);
	long sum = Dvb2Idr(dv) + idr;
	
	sum = __min(sum, MAXIDR);
	sum = __max(sum, MINIDR);
	return(Idr2Dvb(sum, dot));
}


IDR DvbMinus2Idr(uint32_t dv1, uint32_t dv2)
{
	return(Dvb2Idr(dv1) - Dvb2Idr(dv2));
}

BCD Int2Bcd(int iv)
{
	uint16_t bcd = 0;
	int i;

	iv = __min(iv, 9999);
	iv = __max(iv, 0);
	for(i=0; i<4; i++) {
		bcd += (iv%10)<<(4*i);
		iv /= 10;
	}
	return(bcd);
}

int Bcd2Int(BCD bcd)
{
	int multi = 1;
	int iv = 0;
	uint16_t digi;
	int i;

	for(i=0; i<4; i++) {
		digi = (bcd&0x000F);
		digi = __min(digi, 9);
		iv += digi*multi;
		bcd >>= 4;
		multi *= 10;
	}
	return(iv);
}

void Bcd2String(char strBuf[], BCD bcd)
{
	uint16_t digi;
	int i;

	for(i=0; i<4; i++) {
		digi = (bcd&0x000F);
		digi = __min(digi, 9);
		strBuf[3-i] = (char)(digi + '0');
		bcd >>= 4;
	}
	strBuf[4] = '\0';
}

BCD String2Bcd(const char *str)
{
	int len = (int)strlen(str);
	uint16_t bcd = 0;
	uint16_t dchar;
	int i;

	for(i=0; i<len; i++) {
		dchar = str[i];
		dchar = __min(dchar, '9');
		dchar = __max(dchar, '0');
		bcd = (uint16_t)((bcd<<4) + dchar - '0');
	}
	return(bcd);
}
